/**************************************************************************//**
 * @file     spi.h
 * @version  V1.00
 * $Revision: 2 $
 * $Date: 15/05/18 10:44a $
 * @brief    NUC970 SPI driver header file
 *
 * @note
 * SPDX-License-Identifier: Apache-2.0
 * Copyright (C) 2015 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#ifndef __NUC970_SPI_H__
#define __NUC970_SPI_H__

#include "nuc970.h"

#ifdef __cplusplus
extern "C"
{
#endif


/** @addtogroup NUC970_Device_Driver NUC970 Device Driver
  @{
*/

/** @addtogroup NUC970_SPI_Driver SPI Driver
  @{
*/

/** @addtogroup NUC970_SPI_EXPORTED_CONSTANTS SPI Exported Constants
  @{
*/
/// @cond HIDDEN_SYMBOLS

#define REG_CNTRL   0x00    /*!< Control Register Address */
#define REG_DIVIDER 0x04    /*!< Divider Register Address */
#define REG_SSR     0x08    /*!< Slave Select Register Address */
#define REG_RX0     0x10    /*!< Receive Register 0 Address */
#define REG_RX1     0x14    /*!< Receive Register 1 Address */
#define REG_RX2     0x18    /*!< Receive Register 2 Address */
#define REG_RX3     0x1C    /*!< Receive Register 3 Address */
#define REG_TX0     0x10    /*!< Transfer Register 0 Address */
#define REG_TX1     0x14    /*!< Transfer Register 1 Address */
#define REG_TX2     0x18    /*!< Transfer Register 2 Address */
#define REG_TX3     0x1C    /*!< Transfer Register 3 Address */

#define SPI_INPUT_CLOCK			75000000        /* Unit: Hz. */
/// @endcond HIDDEN_SYMBOLS

#define SPI_NUMBER  2       /*!< 2 spi interfaces  */

#define SPI_NO_ERR		0   /*!< No error  */

#define SPI_ERR_NODEV   -1  /*!< Wrong device id  */
#define SPI_ERR_BUSY    -2  /*!< Interface is busy  */
#define SPI_ERR_IO      -3  /*!< IO control error for not opened interface  */
#define SPI_ERR_ARG     -4  /*!< Wrong argument in IO control  */

#define SPI_IOC_TRIGGER                 0   /*!< Trigger SPI interface */
#define SPI_IOC_SET_INTERRUPT           1   /*!< Enable/disable interrupt ,arguments could be \ref SPI_DISABLE_INTERRUPT and \ref SPI_ENABLE_INTERRUPT */
#define SPI_IOC_SET_SPEED               2   /*!< Set SPI clock speed */
#define SPI_IOC_SET_DUAL_QUAD_MODE      3   /*!< Enable/disable Quad/Dual mode ,arguments could be \ref SPI_DISABLE_DUAL_QUAD, \ref SPI_DUAL_MODE, \ref SPI_QUAD_MODE*/
#define SPI_IOC_SET_DUAL_QUAD_DIR       4   /*!< Set Quad/Dual mode direction ,arguments could be \ref SPI_DUAL_QUAD_INPUT, \ref SPI_DUAL_QUAD_OUTPUT */
#define SPI_IOC_SET_LSB_MSB             5   /*!< Set MSB/LSB ,arguments could be \ref SPI_MSB, \ref SPI_LSB */
#define SPI_IOC_SET_TX_NUM              6   /*!< Set transfer number */
#define SPI_IOC_SET_TX_BITLEN           7   /*!< Set transfer bit number */
#define SPI_IOC_SET_MODE                8   /*!< Set SPI mode ,arguments could be \ref SPI_MODE_0, \ref SPI_MODE_1, \ref SPI_MODE_2, \ref SPI_MODE_3 */
#define SPI_IOC_ENABLE_SS               9   /*!< Enable slave select pin */
#define SPI_IOC_DISABLE_SS              10  /*!< Disable slave select pin */
#define SPI_IOC_SET_AUTOSS              11  /*!< Enable/disable auto slave select function ,arguments could be \ref SPI_DISABLE_AUTOSS, \ref SPI_ENABLE_AUTOSS */
#define SPI_IOC_SET_SS_ACTIVE_LEVEL     12  /*!< Set slave select active level ,arguments could be \ref SPI_SS_ACTIVE_LOW, \ref SPI_SS_ACTIVE_HIGH */

#define SPI_DISABLE_INTERRUPT   0   /*!< Disable interrupt */
#define SPI_ENABLE_INTERRUPT    1   /*!< Enable interrupt */

#define SPI_DISABLE_DUAL_QUAD   0   /*!< Disable quad and dual mode */
#define SPI_DUAL_MODE           1   /*!< Enable dual mode */
#define SPI_QUAD_MODE           2   /*!< Enable quad mode */

#define SPI_DUAL_QUAD_INPUT     0   /*!< Set dual/quad mode io direction to input */
#define SPI_DUAL_QUAD_OUTPUT    1   /*!< Set dual/quad mode io direction to output */

#define SPI_MSB                 0   /*!< Enable MSB */
#define SPI_LSB                 1   /*!< Enable LSB */

#define SPI_MODE_0              0   /*!< Set to SPI mode 0 */
#define SPI_MODE_1              1   /*!< Set to SPI mode 1 */
#define SPI_MODE_2              2   /*!< Set to SPI mode 2 */
#define SPI_MODE_3              3   /*!< Set to SPI mode 3 */

#define SPI_SS_SS0              0   /*!< Select SS0 */
#define SPI_SS_SS1              1   /*!< Select SS1 */
#define SPI_SS_BOTH             2   /*!< Select both SS0/SS1 */

#define SPI_DISABLE_AUTOSS      0   /*!< Disable auto slave select function */
#define SPI_ENABLE_AUTOSS       1   /*!< Enable auto slave select function */

#define SPI_SS_ACTIVE_LOW       0   /*!< Set active level of slave select to low */
#define SPI_SS_ACTIVE_HIGH      1   /*!< Set active level of slave select to high */

/*@}*/ /* end of group NUC970_SPI_EXPORTED_CONSTANTS */


/** @addtogroup NUC970_SPI_EXPORTED_STRUCTS SPI Exported Structs
  @{
*/

/// @cond HIDDEN_SYMBOLS
/// @endcond HIDDEN_SYMBOLS

typedef struct
{
    __IO UINT32 CNTRL;                      /*!< Control and Status Register */
    __IO UINT32 DIVIDER;                    /*!< Clock Divider Register */
    __IO UINT32 SSR;                        /*!< Slave Select Register */
    __I UINT32 Reserved;                        /*!< Slave Select Register */
    union {
    __IO UINT32 RXReg[4];                        /*!< Data Receive Register 0 */
    __IO UINT32 TXReg[4];                        /*!< Data Transmit Register 0 */
    }DAT;
#define SPIRX DAT.RXReg
#define SPITX DAT.TXReg
} SPI_TypeDef;

#define SPI0    ((SPI_TypeDef *)SPI0_BA)
#define SPI1    ((SPI_TypeDef *)SPI1_BA)


#define SPI_CNTRL_LSB_Pos               (10)                                            /*!< SPI_TypeDef::CNTRL: LSB Position               */
#define SPI_CNTRL_LSB_Msk               (0x1ul << SPI_CNTRL_LSB_Pos)                    /*!< SPI_TypeDef::CNTRL: LSB Mask                   */

#define SPI_SSR_SS_Pos                  (0)                                             /*!< SPI_TypeDef::SSR: SS Position              */
#define SPI_SSR_SS_Msk                  (0x3ul << SPI_SSR_SS_Pos)                       /*!< SPI_TypeDef::SSR: SS Mask                  */

#define SPI_SSR_LEVEL_Pos               (2)                                             /*!< SPI_TypeDef::SSR: SS_LVL Position        */
#define SPI_SSR_LEVEL_Msk               (0x1ul << SPI_SSR_LEVEL_Pos)                    /*!< SPI_TypeDef::SSR: SS_LVL Mask            */

/**
  * @brief      Set SPIx_SS pin active level.
  * @param[in]  spi The pointer of the specified SPI module.
  * @return     None.
  * @details    Disable automatic slave selection function and set SPIx_SS pin to high state.
  * \hideinitializer
  */
#define SPI_SET_SS_LVL_HIGH(spi)   ((spi)->SSR |= SPI_SSR_LEVEL_Msk)
#define SPI_SET_SS_LVL_LOW(spi)    ((spi)->SSR &= ~SPI_SSR_LEVEL_Msk)

/**
  * @brief      Set SPIx_SS pin to high state.
  * @param[in]  spi The pointer of the specified SPI module.
  * @return     None.
  * @details    Disable automatic slave selection function and set SPIx_SS pin to high state.
  * \hideinitializer
  */
#define SPI_SET_SS_ENABLE(spi, n)   ((spi)->SSR = ((spi)->SSR & (~SPI_SSR_SS_Msk)) | (n&0x3))

/**
  * @brief      Set SPIx_SS pin to low state.
  * @param[in]  spi The pointer of the specified SPI module.
  * @return     None.
  * @details    Disable automatic slave selection function and set SPIx_SS pin to low state.
  * \hideinitializer
  */
#define SPI_SET_SS_DESABLE(spi, n)   ((spi)->SSR = ((spi)->SSR & (~(n&0x3))))

/**
  * @brief      Set the SPI transfer sequence with LSB first.
  * @param[in]  spi The pointer of the specified SPI module.
  * @return     None.
  * @details    Set LSB bit of SPI_CTL register to set the SPI transfer sequence with LSB first.
  * \hideinitializer
  */
#define SPI_SET_LSB_FIRST(spi)   ((spi)->CNTRL |= SPI_CNTRL_LSB_Msk)

/**
  * @brief      Set the SPI transfer sequence with MSB first.
  * @param[in]  spi The pointer of the specified SPI module.
  * @return     None.
  * @details    Clear LSB bit of SPI_CTL register to set the SPI transfer sequence with MSB first.
  * \hideinitializer
  */
#define SPI_SET_MSB_FIRST(spi)   ((spi)->CNTRL &= ~SPI_CNTRL_LSB_Msk)

/*@}*/ /* end of group NUC970_SPI_EXPORTED_STRUCTS */

/** @addtogroup NUC970_SPI_EXPORTED_FUNCTIONS SPI Exported Functions
  @{
*/

int32_t  spiInit(int32_t fd);
int32_t spiIoctl(int32_t fd, uint32_t cmd, uint32_t arg0, uint32_t arg1);
int spiOpen(int32_t fd);
uint8_t spiGetBusyStatus(int32_t fd);
uint32_t spiRead(int32_t fd, uint8_t buff_id);
void spiWrite(int32_t fd, uint8_t buff_id, uint32_t data);

void SPI_Open(SPI_TypeDef *spi, UINT32 speed, UINT32 data_len, UINT32 mode);
UINT32 SPI_Read(SPI_TypeDef *spi, UINT8 buff_ind);
void SPI_Write(SPI_TypeDef *spi, UINT8 buff_ind, UINT32 data);
inline void SPI_Trigger(SPI_TypeDef *spi)
{
    UINT32 reg;

    // trigger
    reg = spi->CNTRL;
    reg |= 0x1;
    spi->CNTRL = reg;
}

inline BOOL SPI_isBusy(SPI_TypeDef *spi)
{
    return ((spi->CNTRL & 0x1) == 0x1);
}

/*@}*/ /* end of group NUC970_SPI_EXPORTED_FUNCTIONS */

/*@}*/ /* end of group NUC970_SPI_Driver */

/*@}*/ /* end of group NUC970_Device_Driver */

#ifdef __cplusplus
}
#endif

#endif // __NUC970_SPI_H__

/*** (C) COPYRIGHT 2015 Nuvoton Technology Corp. ***/
